var BATTLESHIPS = {'Destroyer': 2, 'Cruiser': 3, 'Submarine': 3, 'Battleship': 4, 'Aircraft Carrier': 5};
var GAMESTATES = {PLACINGPHASE: 0, PLAYER1MOVE: 1, PLAYER2MOVE: 2, PLAYER1WIN: 3, PLAYER2WIN: 4};

exports.Game = function (player1, player2) {

    this.player1 = player1;
    this.player2 = player2;
    this.state = GAMESTATES.PLACINGPHASE;
    this.board = {};

    this.board[player1] = {

        ships: {},
        shots: "",
        hits: "",
        misses: ""

    };

    this.board[player2] = {

        ships: {},
        shots: "",
        hits: "",
        misses: ""

    };
};

exports.Game.prototype.getBoardState = function (player) {

    var boardState = {};

    if (player == this.player1) {

        boardState[this.player1] = {ships: this.board[this.player1].ships, hits: this.board[this.player1].hits, misses: this.board[this.player1].misses};
        boardState[this.player2] = {ships: {}, hits: this.board[this.player2].hits, misses: this.board[this.player2].misses};

    } else if (player == this.player2) {

        boardState[this.player1] = {ships: {}, hits: this.board[this.player1].hits, misses: this.board[this.player1].misses};
        boardState[this.player2] = {ships: this.board[this.player2].ships, hits: this.board[this.player2].hits, misses: this.board[this.player2].misses};

    } else {

        boardState[this.player1] = {ships: this.board[this.player1].ships, hits: this.board[this.player1].hits, misses: this.board[this.player1].misses};
        boardState[this.player2] = {ships: this.board[this.player2].ships, hits: this.board[this.player2].hits, misses: this.board[this.player2].misses};

    }

    return boardState;

};

exports.Game.prototype.getGameState = function () {

    return this.state;

};

exports.Game.prototype.isHit = function (player, coord) {

    var firedUponPlayerShips;

    if (player == this.player1) {

        firedUponPlayerShips = this.board[this.player2].ships;

    } else {

        firedUponPlayerShips = this.board[this.player1].ships;

    }

    for (var ship in firedUponPlayerShips) {

        if (firedUponPlayerShips[ship].indexOf(coord) != -1) {

            return true;

        }
    }

    return false;
};

exports.Game.prototype.isValidCoord = function (coord) {

    var x = Number(coord.charAt(1)) + 1;
    var y = coord.charCodeAt(0) - 64;

    console.log("x is: " + x + "   y is: " + y);
    return x >= 1 && x <= 10 && y >= 1 && y <= 10;
};

exports.Game.prototype.isUsedCoord = function (player, coord) {

    for (var ship in this.board[player].ships) {

        if (this.board[player].ships[ship].indexOf(coord) != -1) {

            return true;
        }
    }

    return false;

};

exports.Game.prototype.isPlacingComplete = function () {

    var bShipsLength = count(BATTLESHIPS);

    return (bShipsLength === count(this.board[this.player1].ships) && bShipsLength === count(this.board[this.player2].ships));

};

exports.Game.prototype.isGameOver = function (player) {

    var otherPlayerShips;
    var playerShots = this.board[player].shots;

    if (this.player1 == player) {

        otherPlayerShips = this.board[this.player2].ships;

    } else {

        otherPlayerShips = this.board[this.player1].ships;

    }

    for (var ship in otherPlayerShips) {

        for (var i = 0; i < otherPlayerShips[ship].length; i += 2) {

            if (playerShots.indexOf(otherPlayerShips[ship].substring(i, i + 2)) == -1) {

                return false;

            }

            console.log(otherPlayerShips[ship].substring(i, i + 2));

        }
    }

    return true;
};

exports.Game.prototype.takeShot = function (player, coord) {

    if ((this.state === GAMESTATES.PLAYER1MOVE && this.player1 == player) || (this.state === GAMESTATES.PLAYER2MOVE && this.player2 == player)) {

        if (this.isValidCoord(coord)) {

            if (this.board[player].shots.indexOf(coord) === -1) {

                this.board[player].shots += coord;

                if (this.isHit(player, coord)) {

                    this.board[player].hits += coord;

                } else {

                    this.board[player].misses += coord;

                }

                if (this.isGameOver(player)) {

                    if (this.player1 == player) {

                        this.state = GAMESTATES.PLAYER1WIN;

                    } else {

                        this.state = GAMESTATES.PLAYER2WIN;

                    }

                } else {

                    this.state = ((this.state == GAMESTATES.PLAYER1MOVE) ? GAMESTATES.PLAYER2MOVE : GAMESTATES.PLAYER1MOVE);

                }

                return {status: "success"};

            } else {

                return {status: "A shot was already made at this location"};

            }

        } else {

            return {status: "Shot was not at a valid coordinate"};

        }

    } else {

        return {status: "That's a paddlin..."};

    }
};

exports.Game.prototype.placeShip = function (player, type, pivotPoint, orientation) {

    var shipCoords = "";
    var currentCoord = "";

    if (!(player in this.board)) {

        return {status: "User is not one of the players"};

    }

    if (this.state !== GAMESTATES.PLACINGPHASE) {

        return {status: "Placing phase is over"};

    }

    if (this.isValidCoord(pivotPoint) && type in BATTLESHIPS && !(type in this.board[player].ships)) {

        console.log("pivot valid");
        console.log("The pivot point is: " + pivotPoint);

        switch (orientation) {

            case "Left":

                console.log("The end point is: " + (pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) - BATTLESHIPS[type] + 1)));

                if (this.isValidCoord(pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) - BATTLESHIPS[type] + 1))) {

                    for (var i = 0; i < BATTLESHIPS[type]; i++) {

                        currentCoord = pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) - i);

                        if (!this.isUsedCoord(player, currentCoord)) {

                            shipCoords += currentCoord;

                        } else {

                            shipCoords = "";
                            break;
                        }
                    }
                }
                break;

            case "Right":

                console.log("The end point is: " + pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) + BATTLESHIPS[type] - 1));

                if (this.isValidCoord(pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) + BATTLESHIPS[type] - 1))) {

                    console.log("size valid");

                    for (var i = 0; i < BATTLESHIPS[type]; i++) {

                        currentCoord = pivotPoint.charAt(0) + (Number(pivotPoint.charAt(1)) + i);

                        if (!this.isUsedCoord(player, currentCoord)) {

                            shipCoords += currentCoord;

                        } else {

                            shipCoords = "";
                            break;
                        }
                    }
                }
                break;

            case "Up":

                console.log("The end point is: " + (String.fromCharCode(pivotPoint.charCodeAt(0) - BATTLESHIPS[type] + 1) + (Number(pivotPoint.charAt(1)))));

                if (this.isValidCoord(String.fromCharCode(pivotPoint.charCodeAt(0) - BATTLESHIPS[type] + 1) + pivotPoint.charAt(1))) {

                    for (var i = 0; i < BATTLESHIPS[type]; i++) {

                        currentCoord = String.fromCharCode(pivotPoint.charCodeAt(0) - i) + pivotPoint.charAt(1);

                        if (!this.isUsedCoord(player, currentCoord)) {

                            shipCoords += currentCoord;

                        } else {

                            shipCoords = "";
                            break;
                        }
                    }
                }
                break;

            case "Down":

                console.log("The end point is: " + (String.fromCharCode(pivotPoint.charCodeAt(0) + BATTLESHIPS[type] - 1) + (Number(pivotPoint.charAt(1)))));

                if (this.isValidCoord(String.fromCharCode(pivotPoint.charCodeAt(0) + BATTLESHIPS[type] - 1) + pivotPoint.charAt(1))) {

                    for (var i = 0; i < BATTLESHIPS[type]; i++) {

                        currentCoord = String.fromCharCode(pivotPoint.charCodeAt(0) + i) + pivotPoint.charAt(1);

                        if (!this.isUsedCoord(player, currentCoord)) {

                            shipCoords += currentCoord;

                        } else {

                            shipCoords = "";
                            break;
                        }
                    }
                }
        }
    }

    if (player in this.board && shipCoords != "") {

        this.board[player].ships[type] = shipCoords;
    } else {
        return {status: "failure"};
    }

    if (this.isPlacingComplete()) {

        this.state = GAMESTATES.PLAYER1MOVE;

    }

    return {status: "success"};
};

// The following code was obtained from http://stackoverflow.com/questions/1074365/how-do-i-get-number-of-fields-in-javascript-object
function count(obj) {

    if (obj.__count__ !== undefined) { // Old FF

        return obj.__count__;

    }

    if (Object.keys) { // ES5

        return Object.keys(obj).length;

    }

    // Everything else:

    var c = 0, p;

    for (p in obj) {

        if (obj.hasOwnProperty(p)) {

            c += 1;

        }
    }

    return c;
}